package com.xianggu.schedule;

import com.xianggu.threadPool.MyThreadPool;
import com.xianggu.threadPool.rejectStrategy.DefalutRejectHandle;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @author chengjy
 * @date 2025/3/15
 */
public class ScheduleService {

    //任务队列
    PriorityBlockingQueue<Job> taskList = new PriorityBlockingQueue<>();
    // 处理任务的线程池
    MyThreadPool myThreadPool = new MyThreadPool(2,4, 1000, TimeUnit.MILLISECONDS
            , new ArrayBlockingQueue<>(5), new DefalutRejectHandle());


    // 创建并启动一个新的线程，用于处理任务调度和执行
    Thread thread = thread = new Thread(() -> {
        while (true) {
            // 判断任务列表中是否有任务
            while (taskList.isEmpty()) {
                // 如果没有任务，线程暂停，等待任务被添加
                LockSupport.park();
            }
            // 查看顶上的任务是否符合执行时间
            Job task = taskList.peek();
            if(task.getExecuteTime() < System.currentTimeMillis()){
                // 如果当前时间超过任务的执行时间，取出任务并执行
                task = taskList.poll();
                // 使用线程池执行任务
                myThreadPool.execute(task.getTask());
//                task.getTask().run();
                // 创建下一个周期的任务，并添加到任务列表中
                Job nextTask = new Job(task.getTask() , task.getExecuteTime() + task.getDelay() , task.getDelay());
                taskList.offer(nextTask);
            }else{
                // 如果当前时间未到任务执行时间，计算睡眠时间并让线程睡眠
                long seelpTime = task.getExecuteTime() - System.currentTimeMillis();
                LockSupport.parkUntil(seelpTime);
            }
        }
    });

    {
        thread.start();
    }

    /**
     * 调度任务
     * @param task
     * @param delay
     */
    public void schedule(Runnable task , long delay){
        Job job = new Job(task , delay + System.currentTimeMillis()  , delay);
        taskList.offer(job);
        LockSupport.unpark(thread);
    }

    class Job implements Comparable<Job>{
        private Runnable task;
        private long executeTime;
        private long delay;

        public Runnable getTask() {
            return task;
        }

        public Job(Runnable task, long executeTime, long delay) {
            this.task = task;
            this.executeTime = executeTime;
            this.delay = delay;
        }

        public long getDelay() {
            return delay;
        }

        public long getExecuteTime() {
            return executeTime;
        }

        @Override
        public int compareTo(Job o) {
            return this.executeTime > o.executeTime ? 1 : -1;
        }
    }
}
